/****************************************************************************
** The arrays module implements an abstract array object (adding and 
** removing elements, finding, sorting, etc.), along with concrete element
** types (movies, games, etc.) and array initializers for these concrete
** types (arr_init_movies, etc.)
****************************************************************************/
#ifndef ARRAYS_H_INCLUDED
#define ARRAYS_H_INCLUDED

#include "common.h"

#define ARRAY_CAPACITY_RESIZE		(100)


/****************************************************************************
** ABSTRACT ARRAY OBJECT
****************************************************************************/

/* initializes the given element */
typedef void (*init_t)(void * elem);

/* finalizes the given element */
typedef void (*fini_t)(void * elem);

/* matches the given signature with the given element, returns TRUE if 
the element matches the signature, FALSE otherwise */
typedef success_t (*match_t)(const void * elem, const void * signature);

/* compares two array elements, returns a negative number if elem1 < elem2,
0 if elem1 == elem2, or a positive number if elem1 > elem2 */
typedef int (*compare_t)(const void * elem1, const void * elem2);

/* abstract array object */
typedef struct
{
	int count;
	int capacity;
	int elemsize;
	void * elements;
	init_t init;
	fini_t fini;
	match_t match;
} arr_t;

/* abstract array iterator */
typedef struct
{
	int index;
	const arr_t * arr;
} iterator_t;


/****************************************************************************
** CONCRETE ARRAY ELEMENTS
****************************************************************************/
typedef struct
{
	char name[MAX_LEN];
	int usage;
	int year;
	char genre[MAX_LEN];
} movie_t;

typedef struct
{
	char name[MAX_LEN];
	int score;
} player_t;

typedef struct
{
	char name[MAX_LEN];
	int usage;
	int start_year;
	int end_year;
	arr_t players;
} game_t;

typedef struct
{
	char name[MAX_LEN];
	int usage;
	int songs;
	char genre[MAX_LEN];
} playlist_t;


/****************************************************************************
** ABSTRACT ARRAY FUNCTIONS
****************************************************************************/


/*---------------------------------------------------------------------------
arr_init: initializes the given array object
 
params:
 * self - reference to arr_t object to initialize
 * elemsize - the size (in bytes) of an array element
 * init - element initializer (function pointer). if NULL, no element
   initializer is used
 * fini - element finalizer (function pointer). if NULL, no element 
   finalizer is used
 * match - element matcher (function pointer), used to find an element by
   a signature (e.g., name). if NULL, arr_find() and arr_get() cannot 
   be used.

retval: none
---------------------------------------------------------------------------*/
void arr_init(arr_t * self, int elemsize, init_t init, fini_t fini, 
			  match_t match);

/*---------------------------------------------------------------------------
arr_fini: finalizes the given array object (frees all resources)
 
params:
 * self - reference to arr_t object to finalize

retval: none
---------------------------------------------------------------------------*/
void arr_fini(arr_t * self);

/*---------------------------------------------------------------------------
arr_append: grows the array, appending an element at the end. 
 
params:
 * self - reference to arr_t object to append an element to

retval: pointer to the last element, or NULL if failed to allocate 
sufficient memory for the operation
---------------------------------------------------------------------------*/
void * arr_append(arr_t * self);

/*---------------------------------------------------------------------------
arr_remove: removes an element from the array (by index), shifting down 
all the elements after the one to remove

params:
 * self - reference to arr_t object to initialize
 * index - the index of the element to remove

retval: TRUE if removed successfully, FALSE otherwise (e.g., out of memory)
---------------------------------------------------------------------------*/
success_t arr_remove(arr_t * self, int index);

/*---------------------------------------------------------------------------
arr_find: finds an element in the array by matching the signature of an 
element (e.g., match element name)
 
params:
 * self - reference to arr_t object to initialize
 * signature - a signature object, used by the matcher function to match
 the element to the signature

retval: the INDEX of the matched element, or -1 if element not found
---------------------------------------------------------------------------*/
int arr_find(const arr_t * self, const void * signature);

/*---------------------------------------------------------------------------
arr_get: gets an element from the array (like find, but returns the element
itself instead of the index)
 
params:
 * self - reference to arr_t object to initialize
 * signature - the size (in bytes) of each array element

retval: a pointer to the matched element, or NULL if element not found
---------------------------------------------------------------------------*/
void * arr_get(arr_t * self, const void * signature);

/*---------------------------------------------------------------------------
arr_sort: sorts INPLACE the array, using the given comparator function to
compare between elements
 
params:
 * self - reference to arr_t object to initialize
 * cmp - a comparator (function pointer), returns negative if a < b, 
   0 if a == b, or positive if a > b

retval: none
---------------------------------------------------------------------------*/
void arr_sort(arr_t * self, compare_t cmp);

/*---------------------------------------------------------------------------
arr_getiter: initializes an array iterator for the given array
 
params:
 * self - reference to arr_t object to initialize
 * iter - reference to iterator_t object to initliaze

retval: none
---------------------------------------------------------------------------*/
void arr_getiter(const arr_t * self, iterator_t * iter);

/*---------------------------------------------------------------------------
arr_iternext - retrieves the next element from the array iterator
 
params:
 * self - reference to array iterator object

retval: pointer to the next element, or NULL if reached end
---------------------------------------------------------------------------*/
void * arr_iternext(iterator_t * self);


/****************************************************************************
** CONCRETE ELEMENT FUNCTIONS
****************************************************************************/


/*---------------------------------------------------------------------------
arr_init_movies: initializes the given array object as an array of
movie_t elements
 
params:
 * self - reference to arr_t object to initialize

retval: none
---------------------------------------------------------------------------*/
void arr_init_movies(arr_t * self);

/*---------------------------------------------------------------------------
arr_init_movies: initializes the given array object as an array of
game_t elements
 
params:
 * self - reference to arr_t object to initialize

retval: none
---------------------------------------------------------------------------*/
void arr_init_games(arr_t * self);

/*---------------------------------------------------------------------------
arr_init_movies: initializes the given array object as an array of
playlist_t elements
 
params:
 * self - reference to arr_t object to initialize

retval: none
---------------------------------------------------------------------------*/
void arr_init_playlists(arr_t * self);

/*---------------------------------------------------------------------------
arr_init_movies: initializes the given array object as an array of
player_t elements
 
params:
 * self - reference to arr_t object to initialize

retval: none
---------------------------------------------------------------------------*/
void arr_init_players(arr_t * self);



#endif /* ARRAYS_H_INCLUDED */
